#ifndef __COMPONENT_BODY_HPP__
#define __COMPONENT_BODY_HPP__

#include "Component.hpp"
#include "Engine/Vector3.hpp"
#include "Engine/Quaternion.h"
#include "Engine/BoundingBox.hpp"
#include "Blocks/FluidBlock.h"
#include <mutex>
#include <atomic>
#include "Game/NetType.hpp"
#include "GameAction.hpp"

using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    struct ComponentCreature;
    struct ComponentLocomotion;
    struct ComponentPlayer;
    struct ComponentBody;

    struct CollisionBox
    {
        int32_t blockValue;
        Vector3 blockVelocity;
        ComponentBody *componentBody;
        BoundingBox box;

        constexpr CollisionBox();
        constexpr CollisionBox(int32_t value, const Vector3 &velocity, ComponentBody *body, const BoundingBox &theBox);
    };

    constexpr inline CollisionBox::CollisionBox() : 
        blockValue(0),
        blockVelocity(0),
        componentBody(nullptr) {}

    constexpr inline CollisionBox::CollisionBox(int32_t value, const Vector3 &velocity, ComponentBody *body, const BoundingBox &theBox) : 
        blockValue(value),
        blockVelocity(velocity),
        componentBody(body),
        box(theBox) {}


    struct ComponentBody : public Component
    {
    protected:
        std::atomic<bool> m_positionChange = false;
        std::atomic<bool> m_rotationChange = false;
        std::atomic<bool> m_velocityChange = false;
        std::atomic<bool> m_sneakingChange = false;

        GameAction<ComponentBody* >m_collidedWithBodyEvents;

        std::vector<ComponentBody *> componentBodies;
        std::vector<CollisionBox> collisionBoxes;
        std::vector<CollisionBox> bodiesCollisionBoxes;
        std::vector<CollisionBox> movingBlocksCollisionBoxes;


        // 现在的位置
        Vector3 m_position;
        std::recursive_mutex m_positionMutex;

        // 移动速度
        Vector3 m_velocity;
        std::recursive_mutex m_velocityMutex;

        // 旋转
        Quaternion m_rotation;
        std::recursive_mutex m_rotationMutex;
        

        Matrix m_matrix;
        std::mutex m_matrixMutex;
        bool m_needUpdateMatrix = true;

    public:
        // Vector3 position;
        // Vector3 velocity;
        // Quaternion rotation;
        
        
        // 盒子大小
        Vector3 boxSize;
        // 质量
        float mass;
        // 密度
        float density;
        // 空气阻力
        Vector2 airDrag;
        // 下水阻力
        Vector2 waterDrag;
        // 水摇摆角度
        float waterSwayAngle;
        // 水转向速度
        float waterTurnSpeed;
        // 浸没深度
        float immersionDepth;
        // 浸没系数
        float immersionFactor = 0.0f;
        // 浸没在那种流体方块中
        FluidBlock *immersionFluidBlock = nullptr;
        // 站在哪个方块上面
        int32_t standingOnValue = 0;
        // 站在哪个实体上面
        ComponentBody *standingOnBody = nullptr;
        // 保持速度 ?????
        Vector3 standingOnVelocity;
        // 是否潜行
        bool isSneaking = false;
        // 最大平滑上升高度
        float maxSmoothRiseHeight;
        // 默认密度
        float defaultDensity;

        Vector3 collisionVelocityChange;

        // 挤压受伤时间
        float crushInjureTime;

        Vector3 totalImpulse;
        Vector3 directMove;


        static const std::vector<Vector3> freeSpaceOffsets;

        ComponentLocomotion *componentLocomotion = nullptr;
        ComponentPlayer *componentPlayer = nullptr;
        ComponentCreature *componentCreature = nullptr;

        bool isGravityEnabled;    // 启用重力
        bool isGroundDragEnabled; // 启用地面阻力
        bool isWaterDragEnabled;  // 启用水阻力
        bool isSmoothRiseEnabled; // 启用平滑上升

        virtual void update(float dt) override;
        virtual const std::string &getName() const override;
        static const std::string &GetName();

        virtual void load(const nlohmann::json &jsonData) override;
        virtual void save(nlohmann::json &jsonData) override;
        virtual void saveToMsgJson(nlohmann::json &jsonData) override;

        virtual void updateImmersionData();
        virtual bool moveToFreeSpace(float maxMoveDistance);
        virtual void moveWithCollision(float dt, Vector3 &move);
        virtual bool handleSmoothRise(Vector3 &move, const Vector3 &position, float dt);
        virtual void handleAxisCollision(int32_t axis, float move, Vector3 &position, bool isSmoothRising);
        virtual void findBodiesCollisionBoxes(const Vector3 &position, std::vector<CollisionBox> &result);
        virtual void findMovingBlocksCollisionBoxes(const Vector3 &position, std::vector<CollisionBox> &result);
        virtual void findTerrainCollisionBoxes(const BoundingBox &box, std::vector<CollisionBox> &result);
        virtual void findSneakCollisionBoxes(const Vector3 &position, const Vector2 &overhang, std::vector<CollisionBox> &result);
        virtual bool isColliding(const BoundingBox &box, std::vector<CollisionBox> &collisionBoxes);
        virtual bool isColliding(const BoundingBox &box, std::vector<CollisionBox> &collisionBoxes1, std::vector<CollisionBox> &collisionBoxes2, std::vector<CollisionBox> &collisionBoxes3);

        virtual float calculatePushBack(const BoundingBox &box, int32_t axis, std::vector<CollisionBox> &collisionBoxes, CollisionBox &pushingCollisionBox);
        virtual float calculateSmoothRisePushBack(const BoundingBox &normalBox, const BoundingBox &smoothRiseBox, int32_t axis, std::vector<CollisionBox> &collisionBoxes, CollisionBox &pushingCollisionBox);
        virtual const Matrix &getMatrix();

        void getPosition(Vector3 &outPosition);
        void setPosition(const Vector3 &position);

        void getVelocity(Vector3 &outVelocity);
        void setVelocity(const Vector3 &velocity);

        void getRotation(Quaternion &outRotation);
        void setRotation(const Quaternion &rotation);

        /**
         * @brief 设置是否下蹲
         * @param value true:下蹲，false:站立
         */
        void setSneaking(bool value);


        void applyImpulse(const Vector3 &impulse);
        void applyImpulseNet(const Vector3 &impulse);
        void applyDirectMove(const Vector3 &move);

        // 获取实体的体型框，一般用于体型碰撞计算
        BoundingBox getBoundingBox();

        // 获取标准的体型大小，蹲下和站立的体型大小是不一样的
        Vector3 getStanceBoxSize();


        bool getChangedPosition(Vector3 &pos);
        bool getChangedRotation(Quaternion &rota);
        bool getChangedVelocity(Vector3 &vel);
        bool getSneaking(bool &value);

        void addCollidedWithBodyEvent(std::function<void(ComponentBody*)> event);
    };


} // namespace PocketSurvival

#endif